/**********************************************************************

  Audacity: A Digital Audio Editor

  RingBuffer.h

  Dominic Mazzoni

*******************************************************************/

#ifndef __AUDACITY_RING_BUFFER__
#define __AUDACITY_RING_BUFFER__

#include "SampleFormat.h"
#include <atomic>

class RingBuffer final : public NonInterferingBase
{
public:
    RingBuffer(sampleFormat format, size_t size);
    ~RingBuffer();

    //
    // For the writer only:
    //

    size_t AvailForPut() const;
    //! Reader may concurrently cause a decrease of what this returns
    size_t WrittenForGet() const;
    //! Does not apply dithering
    size_t Put(constSamplePtr buffer, sampleFormat format, size_t samples,
               // optional number of trailing zeroes
               size_t padding = 0);
    //! Remove an initial segment of data that has been Put but not Flushed yet
    /*!
     @return how many were unput
     */
    size_t Unput(size_t size);
    size_t Clear(sampleFormat format, size_t samples);
    //! Get access to written but unflushed data, which is in at most two blocks
    //! Excludes the padding of the most recent Put()
    std::pair<samplePtr, size_t> GetUnflushed(unsigned iBlock);
    //! Flush after a sequence of Put (and/or Clear) calls to let consumer see
    void Flush();

    //
    // For the reader only:
    //

    size_t AvailForGet() const;
    //! Does not apply dithering
    size_t Get(samplePtr buffer, sampleFormat format, size_t samples);
    size_t Discard(size_t samples);

private:
    size_t Filled(size_t start, size_t end) const;
    size_t Free(size_t start, size_t end) const;

    size_t mWritten{ 0 };
    size_t mLastPadding{ 0 };

    // Align the two atomics to avoid false sharing
    NonInterfering< std::atomic<size_t> > mStart{ 0 }, mEnd{ 0 };

    const size_t mBufferSize;

    const sampleFormat mFormat;
    const SampleBuffer mBuffer;
};

#endif /*  __AUDACITY_RING_BUFFER__ */
